package com.MutiModule.common.jdk;

import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;

import java.util.Collection;
import java.util.Collections;
import java.util.Random;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 阻塞队列（BlockingQueue）是一个支持两个附加操作的队列。这两个附加的操作是：
 * 在队列为空时，获取元素的线程会等待队列变为非空。当队列满时，存储元素的线程会等待队列可用。
 * 阻塞队列常用于生产者和消费者的场景，生产者是往队列里添加元素的线程，消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器，而消费者也只从容器里拿元素。
 * 
 * 可以将DelayQueue运用在以下应用场景:
 * 缓存系统的设计：可以用DelayQueue保存缓存元素的有效期，使用一个线程循环查询DelayQueue，一旦能从DelayQueue中获取元素时，表示缓存有效期到了。
 * 定时任务调度。使用DelayQueue保存当天将会执行的任务和执行时间，一旦从DelayQueue中获取到任务就开始执行，从比如TimerQueue就是使用DelayQueue实现的。
 */
/**
 * 只有在延迟期满时才能从中提取元素。它接受实现Delayed接口的实例作为元素
 * 类DelayQueue是一个无界阻塞队列，往队列中插入数据的操作（生产者）永远不会被阻塞，而只有获取数据的操作（消费者）才会被阻塞。
 * 类DelayedTasker维护一个DelayQueue<DelayedTask> queue，其中DelayedTask实现了Delayed接口，并由一个内部类定义
 * 外部类和内部类都实现Runnable接口，对于外部类来说，它的run方法是按定义的时间先后取出队列中的任务，而这些任务即内部类的实例，内部类的run方法定义每个线程具体逻辑
 * @author alexgaoyh
 *
 */
public class DelayedTasker implements Runnable {
	
	DelayQueue<DelayedTask> queue = new DelayQueue<DelayedTask>();

	public void addTask(DelayedTask e) {
		queue.put(e);
	}

	public void removeTask() {
		queue.poll();
	}

	public Collection<DelayedTask> getAllTasks() {
		return Collections.unmodifiableCollection(queue);
	}

	public int getTaskQuantity() {
		return queue.size();
	}

	public void run() {
		while (!queue.isEmpty())
			try {
				queue.take().run();
			} catch (InterruptedException e) {
				System.out.println("Interrupted");
			}
		System.out.println("Finished DelayedTask");
	}

	public static class DelayedTask implements Delayed, Runnable {
		private static int counter = 0;
		private final int id = counter++;
		private final int delta;
		private final long trigger;

		public DelayedTask(int delayInSeconds) {
			delta = delayInSeconds;
			trigger = System.nanoTime() + NANOSECONDS.convert(delta, SECONDS);
		}

		public long getDelay(TimeUnit unit) {
			return unit.convert(trigger - System.nanoTime(), NANOSECONDS);
		}

		public int compareTo(Delayed arg) {
			DelayedTask that = (DelayedTask) arg;
			if (trigger < that.trigger)
				return -1;
			if (trigger > that.trigger)
				return 1;
			return 0;
		}

		public void run() {
			// run all that you want to do
			System.out.println(this);
		}

		public String toString() {
			return "[" + delta + "s]" + "Task" + id;
		}
	}

	public static void main(String[] args) {
		Random rand = new Random();
		ExecutorService exec = Executors.newCachedThreadPool();
		
		DelayedTasker tasker = new DelayedTasker();
		for (int i = 0; i < 10; i++) {
			//构造函数，延迟多少秒
			tasker.addTask(new DelayedTask(rand.nextInt(5)));
		}
		
		exec.execute(tasker);
		exec.shutdown();
	}
}